﻿using System;
using System.Collections.Generic;
using System.IO;
using Beaker.Specs;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenCube.IO.Specs.Builders;
using OpenCube.Nbt.Specs.Builders;

namespace OpenCube.Nbt.Specs
{
	[TestClass]
	[CLSCompliant(false)]
	public class NbtDeserializerSpecs
		: SpecsFor<NbtDeserializer, NbtDeserializerBuilder>
	{
		[TestMethod]
		public void StringDeserializesCorrectly()
		{
			Stream stream = new NbtStreamBuilder()
				.AppendCompound("FooBar")
					.AppendString("Foo", "Bar")
					.EndCompound()
				.Build();

			INbtDictionary result = Subject.Deserialize(stream);

			result["Foo"].Should().Be("Bar");
		}

		[TestMethod]
		public void SByteDeserializesCorrectly()
		{
			Stream stream = new NbtStreamBuilder()
				.AppendCompound("FooBar")
					.AppendSByte("Foo", -25)
					.EndCompound()
				.Build();

			INbtDictionary result = Subject.Deserialize(stream);

			result["Foo"].Should().Be((sbyte)-25);
		}

		[TestMethod]
		public void ShortDeserializesCorrectly()
		{
			Stream stream = new NbtStreamBuilder()
				.AppendCompound("FooBar")
					.AppendInt16("Foo", 31415)
					.EndCompound()
				.Build();

			INbtDictionary result = Subject.Deserialize(stream);

			result["Foo"].Should().Be((short)31415);
		}

		[TestMethod]
		public void IntDeserializesCorrectly()
		{
			Stream stream = new NbtStreamBuilder()
				.AppendCompound("FooBar")
					.AppendInt32("Foo", 314159265)
					.EndCompound()
				.Build();

			INbtDictionary result = Subject.Deserialize(stream);

			result["Foo"].Should().Be(314159265);
		}

		[TestMethod]
		public void LongDeserializesCorrectly()
		{
			Stream stream = new NbtStreamBuilder()
				.AppendCompound("FooBar")
					.AppendInt64("Foo", 3141592653589793238)
					.EndCompound()
				.Build();

			INbtDictionary result = Subject.Deserialize(stream);

			result["Foo"].Should().Be(3141592653589793238);
		}

		[TestMethod]
		public void ListOfIntDeserializesCorrectly()
		{
			Stream stream = new NbtStreamBuilder()
				.AppendCompound("FooBar")
					.AppendListOfInt32("Foo", 3, 1, 4, 1, 5, 9, 2, 6, 5)
					.EndCompound()
				.Build();

			INbtDictionary result = Subject.Deserialize(stream);

			((IList<int>)result["Foo"]).Should().ContainInOrder(new int[] { 3, 1, 4, 1, 5, 9, 2, 6, 5 });
		}

		[TestMethod]
		public void MultipleNestedCompoundsDeserializeCorrectly()
		{
			Stream stream = new NbtStreamBuilder()
				.AppendCompound("Root")
					.AppendCompound("Inner")
						.AppendString("Foo", "Bar")
						.EndCompound()
					.EndCompound()
				.Build();

			dynamic result = Subject.Deserialize(stream);

			dynamic inner = result.Inner;
			string foo = inner.Foo;
			foo.Should().Be("Bar");
		}

		/// <summary>
		/// The, as a resource stored, original level.dat file should deserialized without any error
		/// </summary>
		[TestMethod]
		public void OriginalLevelDataShouldDeserializeWithoutErrors()
		{
			Stream stream = new ResourceStreamBuilder()
				.NearType(GetType())
				.InFolder("Resources")
				.WithFilename("level.dat")
				.Build();

			INbtDictionary result = Subject.Deserialize(stream);
		}
	}
}
